import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, CreateAxiosDefaults, InternalAxiosRequestConfig } from "axios";
import axios from "axios";

export type InResponseDetails = { [key: string]: unknown }
export type ResponseDetails<T extends InResponseDetails> = { code: string; data: T; message: string; }
type ResponseDetailsFunctionMethodRecord<T extends InResponseDetails> = Record<string, (response: AxiosResponse<ResponseDetails<T>, unknown>) => AxiosResponse<ResponseDetails<T>, unknown> | never | undefined>
type ResponseDetailsErrorMethod = Record<string, () => string>
/**
 * 生成处理响应数据的函数方法对象。
 *
 * @template T 响应详情的类型，继承自 InResponseDetails 接口。
 * @returns 一个包含处理响应数据的函数方法的对象。
 */
const responseDetailsFunctionMethod = <T extends InResponseDetails>() => ({
  "2000": (response: AxiosResponse<ResponseDetails<T>, unknown>) => response,
  "4000": (response: AxiosResponse<ResponseDetails<T>, unknown>) => createAxiosServiceLessConfigErrorFunction().requestInterceptor(response.data.message),
} as ResponseDetailsFunctionMethodRecord<T>)

/**
 * 返回一个包含错误信息的对象，用于描述响应细节中的错误。
 *
 * @returns 一个包含错误信息的对象，键是错误信息，值是对应的错误代码。
 */
const responseDetailsErrorMethod = () => ({
  "Invalid URL": () => "无效的URL",
  "Network Error": () => "网络错误",
} as ResponseDetailsErrorMethod)

/**
 * 创建一个获取指定cookie值以及修改请求配置的函数对象
 *
 * @returns 一个包含获取cookie值和修改请求配置的函数对象
 */
const createGetCookieStringByKeyFunction = () => ({
  cookie: (key: string) => useCookie(key)?.value,
  requestConfig: (key: string | null | undefined, prame: InternalAxiosRequestConfig) => {
    if (key !== undefined) { prame.headers.Authorization = `Jwt ${key}` }
    return prame;
  }
})

/**
 * 创建一个包含axios服务错误处理函数的配置对象
 *
 * @returns 包含错误处理函数的配置对象
 */
const createAxiosServiceLessConfigErrorFunction = () => ({
  requestError: (err: Error) => { throw err },
  responseError: (err: Error) => { throw err },
  requestInterceptor: (errMsg: string) => { throw new Error(errMsg) },
})

/**
 * 获取包含处理响应和请求方法的对象。
 *
 * @returns 包含处理响应和请求方法的对象。
 */
const getResponseFunctionMethodByResponseDataCodeFunction = () => ({
  response: <T extends InResponseDetails>(response: AxiosResponse<ResponseDetails<T>, unknown>) => {
    if (responseDetailsFunctionMethod<T>()[response.data.code] == undefined) { createAxiosServiceLessConfigErrorFunction().requestInterceptor(`未知的响应状态码: ${response.data.code}`) }
    return response;
  },
  request: (key: string, config: InternalAxiosRequestConfig<any>) => createGetCookieStringByKeyFunction().requestConfig(createGetCookieStringByKeyFunction().cookie(key), config),
})

/**
 * 添加拦截器函数
 *
 * @returns 包含响应和请求拦截器的对象
 */
const addInterceptorHttpCientContenterFunction = () => ({
  response: <T extends InResponseDetails>(axiosInstance: AxiosInstance) => axiosInstance.interceptors.response.use(
    (response) => getResponseFunctionMethodByResponseDataCodeFunction().response<T>(response),
    (error) => createAxiosServiceLessConfigErrorFunction().responseError(error),
  ),
  request: (axiosInstance: AxiosInstance, key: string) => axiosInstance.interceptors.request.use(
    (config) => getResponseFunctionMethodByResponseDataCodeFunction().request(key, config),
    (error) => createAxiosServiceLessConfigErrorFunction().requestError(error),
  ),
})

/**
 * 创建一个axios服务无函数对象
 *
 * @returns 一个包含配置和客户端创建方法的对象
 */
const createAxiosServiceLessFunction = () => ({
  config: (baseUrl: string, timeout: number) => ({ baseURL: baseUrl, timeout: timeout, headers: { "Content-Type": "application/json" } }) as CreateAxiosDefaults,
  client: (prame: CreateAxiosDefaults) => axios.create(prame),
  getRuntimeConfig: (key: string) => <string | undefined>useRuntimeConfig().public[key],
  getRuntimeConfigByKey: (defaultValue: string, key?: string) => key != undefined ? key : defaultValue,
});

// 显示失败提示的函数方法
const showErrorMessage = (err?: Error) => err ? showFailToast(responseDetailsErrorMethod()[err.message]() ? responseDetailsErrorMethod()[err.message]() : "发生未知错误") : undefined;

/**
 * 创建axios客户端请求函数
 *
 * @param url 请求的URL地址
 * @param timeOut 请求超时时间（毫秒）
 * @param key 请求的认证密钥
 * @returns 返回axios客户端的请求函数
 */
export const axiosClient = <T extends InResponseDetails>(url: string, timeOut: number, key: string) => {
  const httpClient = createAxiosServiceLessFunction().client(createAxiosServiceLessFunction().config(url, timeOut))
  addInterceptorHttpCientContenterFunction().request(httpClient, key)
  addInterceptorHttpCientContenterFunction().response<T>(httpClient)
  return httpClient.request;
}

/**
 * 定义 HTTP 客户端函数，用于通过 Axios 发送 HTTP 请求。
 *
 * @param T 泛型参数，指定响应数据的类型，应继承自 InResponseDetails 接口。
 * @returns 返回一个函数，该函数通过 Axios 发送 HTTP 请求并返回响应数据。
 */
export const axiosDefineHttpClient = <T extends InResponseDetails>() => axiosClient<T>(
  createAxiosServiceLessFunction().getRuntimeConfigByKey("http://127.0.0.1:3000", "serviceAdress"),
  Number(createAxiosServiceLessFunction().getRuntimeConfigByKey("3000", "serviceTimeOut")),
  "userToken"
)

/**
 * 异步数据获取函数工厂
 *
 * @param params Axios请求配置
 * @returns 包含异步数据获取函数的对象
 */
export const getAsyncDataFunction = <T extends InResponseDetails>(params: AxiosRequestConfig) => ({
  useAsyncData: async (key: string) => {
    const { error, data, clear, refresh, execute, status } = await useAsyncData<T>(key, () => axiosDefineHttpClient<T>()(params));
    showErrorMessage(error.value as Error)
    return { data, clear, refresh, execute, status }
  },
  useLazyAsyncData: async (key: string) => {
    const { error, data, clear, refresh, execute, status } = await useLazyAsyncData<T>(key, () => axiosDefineHttpClient<T>()(params));
    showErrorMessage(error.value as Error)
    return { data, clear, refresh, execute, status }
  }
})
